<template>
  <view class="aster-tabbar">
    <view
      class="aster-tabbar__content"
      ref="aster-tabbar__content"
      :class="[border && 'aster-border-top', fixed && 'aster-tabbar--fixed']"
      :style="tabbarStyle"
      @touchmove.stop.prevent=""
    >
      <view class="aster-tabbar__content__item-wrapper">
        <slot></slot>
      </view>
      <view class="aster-safe-bottom" :style="safeStyle" />
    </view>
    <view
      class="aster-tabbar__placeholder"
      v-if="placeholder"
      :style="{
        height: placeholderHeight + 'px',
      }"
    />
  </view>
</template>

<script lang="ts" setup>
  import { addStyle, addUnit, deepMerge, sleep } from '@/utils';
  import {
    ref,
    computed,
    watch,
    onMounted,
    getCurrentInstance,
    reactive,
    CSSProperties,
  } from 'vue';

  // 获取组件实例
  const instance = getCurrentInstance();

  const props = defineProps({
    // 当前匹配项的name
    value: {
      type: String,
      default: null,
    },
    // 是否显示上方边框
    border: {
      type: Boolean,
      default: true,
    },
    // 元素层级z-index
    zIndex: {
      type: Number,
      default: 1,
    },
    // 选中标签的颜色
    activeColor: {
      type: String,
      default: '#1989fa',
    },
    // 未选中标签的颜色
    inactiveColor: {
      type: String,
      default: '#7d7e80',
    },
    // 是否固定在底部
    fixed: {
      type: Boolean,
      default: true,
    },
    // fixed定位固定在底部时，是否生成一个等高元素防止塌陷
    placeholder: {
      type: Boolean,
      default: true,
    },
    // 自定义样式
    customStyle: {
      type: Object,
      default: () => {},
    },
  });

  const placeholderHeight = ref(0);
  const children: any = ref([]);

  const tabbarStyle = computed(() => {
    const style = {
      zIndex: props.zIndex,
    };
    // 合并来自父组件的customStyle样式
    return deepMerge(style, addStyle(props.customStyle));
  });

  const safeStyle = () => {
    const style: CSSProperties = reactive({});
    // #ifdef APP-NVUE
    // nvue下，高度使用js计算填充
    style.height = addUnit(uni.getSystemInfoSync().safeAreaInsets?.bottom, 'px');
    // #endif
    return style;
  };

  // 监听多个参数的变化，通过在computed执行对应的操作
  const updateChild = computed(() => {
    return [props.value, props.activeColor, props.inactiveColor];
  });
  const updatePlaceholder = computed(() => {
    return [props.fixed, props.placeholder];
  });

  watch(
    () => updateChild,
    (newValue, oldValue) => {
      updateChildren();
    },
  );

  watch(
    () => updatePlaceholder,
    (newValue, oldValue) => {
      setPlaceholderHeight();
    },
  );

  onMounted(() => {
    setPlaceholderHeight();
  });

  const updateChildren = () => {
    // 如果存在子元素，则执行子元素的updateFromParent进行更新数据
    children.value.length && children.value.map((child: any) => child.updateFromParent());
  };
  // 设置用于防止塌陷元素的高度
  const setPlaceholderHeight = async () => {
    if (!props.fixed || !props.placeholder) return;
    // 延时一定时间
    await sleep(20);
    uGetRect('.aster-tabbar__content').then((res: any) => {
      // 修复IOS safearea bottom 未填充高度
      placeholderHeight.value = res.height ? res.height : 50;
    });
  };

  const uGetRect = (selector: any, all?: any) => {
    return new Promise((resolve) => {
      uni
        .createSelectorQuery()
        .in(instance)
        [all ? 'selectAll' : 'select'](selector)
        .boundingClientRect((rect) => {
          if (all && Array.isArray(rect) && rect.length) {
            resolve(rect);
          }
          if (!all && rect) {
            resolve(rect);
          }
        })
        .exec();
    });
  };
</script>

<style lang="scss" scoped>
  view,
  scroll-view,
  swiper-item {
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
    flex-grow: 0;
    flex-basis: auto;
    align-items: stretch;
    align-content: flex-start;
  }

  .aster-tabbar {
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    flex-direction: column;
    flex: 1;
    justify-content: center;

    &__content {
      /* #ifndef APP-NVUE */
      display: flex;
      /* #endif */
      flex-direction: column;
      background-color: #fff;

      &__item-wrapper {
        height: 50px;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        flex-direction: row;
      }
    }

    &--fixed {
      position: fixed;
      bottom: 0;
      left: 0;
      right: 0;
    }
  }

  .aster-safe-bottom {
    /* #ifndef APP-NVUE */
    width: 100%;
    /* #endif */
  }

  .aster-border-top {
    border-top-width: 0.5px !important;
    border-color: #dadbde !important;
    border-top-style: solid;
  }
</style>
